package com.cdtu.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdtu.entity.*;
import com.cdtu.service.*;
import com.cdtu.util.RedisConst;
import com.cdtu.vo.AddTaskVo;
import com.cdtu.vo.R;
import com.cdtu.vo.TaskDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BulkMapper;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;


/**
 * @author : Sakura
 * @Date : 2022/12/31 21:49
 */
@RestController
@RequestMapping("/task")
//解决跨域问题
@CrossOrigin
public class TaskController {
    @Autowired
    private TaskService taskService;

    @Autowired
    private UserService userService;

    @Autowired
    private RUserTaskService rUserTaskService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private CertifyTypeService  certifyTypeService;
    @Autowired
    private RUserCertifyService rUserCertifyService;
    @Autowired
    private CertifyService certifyService;
    @Autowired
    private AdminService adminService;

//    @GetMapping("/findAll")
//    public List<Category> queryResource(){
//
//        List<Category> list=new ArrayList<>();
//        list.add(new Category(1,"全部"));
//        list.add(new Category(2,"急救"));
//        list.add(new Category(3,"救援"));
//        list.add(new Category(4,"卫生"));
//        list.add(new Category(5,"心理"));
//        return list;
//    }

    @GetMapping("/Detail/{tid}/{oid}")
    public R getTaskDetail(@PathVariable("tid") long tid,
                           @PathVariable("oid") String oid){
//        System.out.println("tid是"+tid);
        LambdaQueryWrapper<User> userWrapper=new LambdaQueryWrapper<>();
        userWrapper.eq(User::getOpenid,oid);
        User user = userService.getOne(userWrapper);
//        LambdaQueryWrapper<RUserTask> queryWrapper=new LambdaQueryWrapper<>();
//        queryWrapper.eq(RUserTask::getId,tid);
        Task task = taskService.getById(tid);
        TaskDTO taskDTO = BeanUtil.copyProperties(task, TaskDTO.class, "startTime");

        LambdaQueryWrapper<RUserTask> taskWrapper=new LambdaQueryWrapper<>();
        taskWrapper.eq(RUserTask::getTaskId,tid);
        List<RUserTask> list = rUserTaskService.list(taskWrapper);
        int count = (int)list.stream().count();
        String key = RedisConst.TASK+tid;
        String json = redisTemplate.opsForValue().get(key);
        if (!StrUtil.hasBlank(json)){
            AddTaskVo addTaskVo = JSONUtil.toBean(json, AddTaskVo.class);
            count += addTaskVo.getDesignateUserList().size();
        }
        taskDTO.setSurplus(task.getUserNum()-count);

        if (count>=task.getUserNum()){
            taskDTO.setFulled(true);
        }
        taskWrapper.eq(RUserTask::getUserId,user.getId());
        RUserTask rUserTask = rUserTaskService.getOne(taskWrapper);

        if (rUserTask!=null){
           taskDTO.setJoined(true);
        }
        taskDTO.setStartTime(task.getStartTime());
        long StartTime = task.getStartTime().getTime();
        long now = new Date().getTime();
        taskDTO.setSurplusTime(StartTime-now);
        return R.success(taskDTO);
    }

    Lock lock = new ReentrantLock();

    @PutMapping("/apply/{tid}/{oid}")
    public R applyActivity(@PathVariable("tid") long tid,
                           @PathVariable("oid") String oid){
//        System.out.println(oid);
//        System.out.println(tid);
//        在这里查询人数多少，还差多少。如果满了就不能报名了


        LambdaQueryWrapper<User> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getOpenid,oid);
        User user = userService.getOne(queryWrapper);
        RUserTask rUserTask=new RUserTask();
        rUserTask.setTaskId(tid);
        rUserTask.setUserId(user.getId());
        Task task = taskService.getById(tid);
        LambdaQueryWrapper<RUserTask> taskWrapper = new LambdaQueryWrapper();
        taskWrapper.eq(RUserTask::getTaskId,tid);
        long count = rUserTaskService.count(taskWrapper);
//        开启锁
        lock.lock();
        try {
            if (task.getUserNum()>count){
                boolean result = rUserTaskService.save(rUserTask);
                if (!result){
                    return R.error("参加失败，请稍后再尝试");
                }
            }
        }finally {
            lock.unlock();
        }


        return R.success("参与成功,请注意活动时间");
    }

    @GetMapping("/taskList/{pageNow}/{pageSize}/{type}/{uid}")
    public R getAllTask(@PathVariable("pageNow") Integer pageNow,
                        @PathVariable("pageSize") Integer pageSize,
                        @PathVariable("type") int type,
                        @PathVariable("uid") long uid
                        ){
        //type为0，查询推荐任务
        if (type==1){
            User user = userService.getById(uid);
            //人员持有的证书id集合
            List<Long> rUserCertifyList = rUserCertifyService.findByUserId(uid);
            //所有的任务集合
            List<Task> taskList = taskService.list();
//            得到人员的等级
            String userGrade = user.getGrade();

//            LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<>();
            //只能挑战最底层的任务
            //        a  -1/0
//                    b 1/0/-1
//                    c 1/0 当比较结果大于等于0，说明只能向下兼容，a型能兼容abc,b型能兼容bc
            List<Task> collect = taskList.stream().filter(task -> task.getGrade().compareTo(userGrade) >= 0)
                    .collect(Collectors.toList());

            List<TaskDTO> dtoList=new ArrayList<>();
            for (int i = 0; i < taskList.size(); i++) {
                Task task = taskList.get(i);
                String key = RedisConst.TASK + task.getId();
                if (redisTemplate.hasKey(key)){
                    String json = redisTemplate.opsForValue().get(key);
                    AddTaskVo addTaskVo = JSONUtil.toBean(json, AddTaskVo.class);
//                    这个任务需要对应证书类型的人才
                    List<Long> actCertify = addTaskVo.getActCertify();
//                    如果这个人持有的证书的类型属于这个类型，就说明这个任务可以被这个人参加
                    for (Long aLong : rUserCertifyList) {
//                        RUserCertify rUserCertify = rUserCertifyService.getById(aLong);
                        Certify certify = certifyService.getById(aLong);
                        if (actCertify.contains(certify.getTypeId())){
                            //存在说明这个任务应该展示参加人员的数量
                            TaskDTO dto = BeanUtil.copyProperties(task, TaskDTO.class);
                            LambdaQueryWrapper<RUserTask> taskLambdaQueryWrapper=new LambdaQueryWrapper<>();
                            taskLambdaQueryWrapper.eq(RUserTask::getTaskId,task.getId());
                            List<RUserTask> rUserTaskList = rUserTaskService.list(taskLambdaQueryWrapper);
                            long count = rUserTaskList.stream().count();
                            count += addTaskVo.getDesignateUserList().size();
                            dto.setJoinNum(count);
                            long StartTime = task.getStartTime().getTime();
                            long now = new Date().getTime();
                            dto.setSurplusTime(StartTime-now);
                            dtoList.add(dto);
                            break;
                        }
                    }
                    }
                }
                //缓存没有怎么样呢？不管了直接不要，抛弃
            //证书匹配的被推荐之后就是过滤等级低的志愿者也能参加的了
            for (Task task : collect) {
                Long tid = task.getId();
                TaskDTO dto = BeanUtil.copyProperties(task, TaskDTO.class);
                LambdaQueryWrapper<RUserTask> taskLambdaQueryWrapper=new LambdaQueryWrapper<>();
                taskLambdaQueryWrapper.eq(RUserTask::getTaskId,task.getId());
                List<RUserTask> rUserTaskList = rUserTaskService.list(taskLambdaQueryWrapper);
                long count = rUserTaskList.stream().count();
                dto.setJoinNum(count);
                long StartTime = task.getStartTime().getTime();
                long now = new Date().getTime();
                dto.setSurplusTime(StartTime-now);
                dtoList.add(dto);
            }
            int start = (pageNow-1)*pageSize;
            List<TaskDTO> dtoList1 = dtoList.stream().sorted(Comparator
                    .comparing(TaskDTO::getStartTime).reversed())
                    .skip(start).limit(pageSize).distinct().collect(Collectors.toList());
            return R.success(dtoList1);
        }

        Page<Task> page=new Page<>(pageNow,pageSize);
        Page<Task> taskPage = taskService.page(page);
//        Page<TaskDTO> taskPageDTO = new Page<>();
        List<Task> list = taskPage.getRecords();

        List<TaskDTO> dtoList=new ArrayList<>();
        for (Task task : list) {
            TaskDTO dto = BeanUtil.copyProperties(task, TaskDTO.class);
            LambdaQueryWrapper<RUserTask> taskLambdaQueryWrapper=new LambdaQueryWrapper<>();
            taskLambdaQueryWrapper.eq(RUserTask::getTaskId,task.getId());
            List<RUserTask> rUserTaskList = rUserTaskService.list(taskLambdaQueryWrapper);
            long count = rUserTaskList.stream().count();
            String key = RedisConst.TASK+task.getId();
            String json = redisTemplate.opsForValue().get(key);
            if (!StrUtil.hasBlank(json)){
                AddTaskVo addTaskVo = JSONUtil.toBean(json, AddTaskVo.class);
                count += addTaskVo.getDesignateUserList().size();
            }
            dto.setJoinNum(count);
            long StartTime = task.getStartTime().getTime();
            long now = new Date().getTime();
            dto.setSurplusTime(StartTime-now);
            dtoList.add(dto);
        }
        dtoList = dtoList.stream().sorted(Comparator
                        .comparing(TaskDTO::getStartTime).reversed())
                .sorted(Comparator
                        .comparing(TaskDTO::getId).reversed())
                .collect(Collectors.toList());

        return R.success(dtoList);
    }


    @GetMapping("/EmeTask/{pageNow}")
    public R getEmeTasks(@PathVariable("pageNow")int pageNow){
        Page<Task> page=new Page<>(pageNow,5);
        LambdaQueryWrapper<Task> taskWrapper=new LambdaQueryWrapper<>();
        taskWrapper.eq(Task::getUrgent,1);
        taskWrapper.ge(Task::getStartTime,new Date());
        Page<Task> taskPage = taskService.page(page,taskWrapper);
        List<Task> list = taskPage.getRecords();
        List<TaskDTO> dtoList=new ArrayList<>();
        for (Task task : list) {
            TaskDTO dto = BeanUtil.copyProperties(task, TaskDTO.class);
            LambdaQueryWrapper<RUserTask> taskLambdaQueryWrapper=new LambdaQueryWrapper<>();
            taskLambdaQueryWrapper.eq(RUserTask::getTaskId,task.getId());
            List<RUserTask> rUserTaskList = rUserTaskService.list(taskLambdaQueryWrapper);
            long count = rUserTaskList.stream().count();
            String key = RedisConst.TASK+task.getId();
            String json = redisTemplate.opsForValue().get(key);
            if (!StrUtil.hasBlank(json)){
                AddTaskVo addTaskVo = JSONUtil.toBean(json, AddTaskVo.class);
                count += addTaskVo.getDesignateUserList().size();
            }
            dto.setJoinNum(count);
            long StartTime = task.getStartTime().getTime();
            long now = new Date().getTime();
            dto.setSurplusTime(StartTime-now);
            dtoList.add(dto);
        }
        return R.success(dtoList);
    }

    /**
     * 查询任务详细情况
     * @param search:
     * @param status:
     * @return R
     * @author Sakura
     * @date 2023/3/10 9:15
     */

    @GetMapping("/getAll")
    public R getTaskList(@RequestParam("search") String search,
                         @RequestParam("status") String status){
//        System.out.println("search："+search);
//        System.out.println("status："+status);
        LambdaQueryWrapper<Task> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StrUtil.isNotEmpty(search),Task::getTitle,search);
        if ("undefined".equals(search)|| "".equals(search)){
            List<Task> list = taskService.list();
            if ("0".equals(status)||"undefined".equals(search)){
                return R.success(list);
            }
            //进行中
            if ("1".equals(status)||"undefined".equals(search)){
                List<Task> collect = list.stream().filter(task -> task.getEndTime().getTime() > new Date().getTime())
                        .collect(Collectors.toList());
                return R.success(collect);
            }
            //已结束
            List<Task> collect = list.stream().filter(task -> task.getEndTime().getTime() < new Date().getTime())
                    .collect(Collectors.toList());
            return R.success(collect);
        }

        List<Task> list = taskService.list(queryWrapper);
        if ("0".equals(status)||"undefined".equals(search)){
            return R.success(list);
        }
        //进行中
        if ("1".equals(status)||"undefined".equals(search)){
            List<Task> collect = list.stream().filter(task -> task.getEndTime().getTime() > new Date().getTime())
                    .collect(Collectors.toList());
            return R.success(collect);
        }
        //已结束
        List<Task> collect = list.stream().filter(task -> task.getEndTime().getTime() < new Date().getTime())
                .collect(Collectors.toList());
        return R.success(collect);
    }

    /**
     * 删除任务
     * @param tid:
     * @return R
     * @author Sakura
     * @date 2023/3/9 18:43
     */
    @Transactional
    @DeleteMapping("/delete/{tid}")
    public R getTaskList(@PathVariable("tid") long tid){
        System.out.println(tid);
        boolean result = taskService.removeById(tid);
        if (!result){
            return R.error("删除失败，请稍后尝试");
        }

        LambdaQueryWrapper<RUserTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RUserTask::getTaskId,tid);
        result = rUserTaskService.removeByUid(tid);
        //这里不能判断，因为如果数据库中没有人，就会显示删除失败
//        if (!result){
//            return R.error("删除失败,请稍后尝试");
//        }
       //删除对应的redis缓存
        redisTemplate.delete(RedisConst.TASK+tid);
        return R.success("删除成功");
    }

    @GetMapping("/detail/{tid}")
    public R getTaskDetailByAdmin(@PathVariable("tid") long tid){
//        System.out.println("tid是"+tid);
        String key = RedisConst.TASK+tid;
        Task task = taskService.getById(tid);
        AddTaskVo vo=new AddTaskVo();
        BeanUtil.copyProperties(task,vo);
        vo.setFinished(task.getEndTime().getTime()<new Date().getTime()?true:false);
        LambdaQueryWrapper<RUserTask> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(RUserTask::getTaskId,tid);
        List<RUserTask> userTaskList = rUserTaskService.list(queryWrapper);
        List<User> userList =new ArrayList<>();
        for (RUserTask rUserTask : userTaskList) {
            Long uid = rUserTask.getUserId();
            userList.add(userService.getById(uid));
        }
//        List<User> joinedUser = vo.getJoinedUser();
        String json = redisTemplate.opsForValue().get(key);
                if (!StrUtil.hasBlank(json)){
                    AddTaskVo addTaskVo = JSONUtil.toBean(json, AddTaskVo.class);
                    List<Long> actCertify = addTaskVo.getActiveUserList();
                    for (Long aLong : actCertify) {
                        User user = userService.getById(aLong);
                        userList.add(user);
                    }
                    List<User> designateUserList = addTaskVo.getDesignateUserList();
                    vo.setPrepareUser(designateUserList);
                }
        long publishUser = task.getPublishUser();
        Admin admin = adminService.getById(publishUser);
        vo.setAdmin(admin);

        vo.setJoinedUser(userList);
        return R.success(vo);
    }

    @GetMapping("/getNav")
    public R getNvList(){
//        LambdaQueryWrapper<CertifyType> typeWrapper = new LambdaQueryWrapper<>();
        List<CertifyType> list = certifyTypeService.list();

        return R.success(list);
    }


}
